package com.tangsm.spring.boot.api.base;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.tangsm.spring.boot.api.enums.ResultCode;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;

import java.io.Serializable;
import java.text.MessageFormat;

/**
 * 统一响应消息报文
 *
 * @param <T> 　T数据对象
 * @author tangsm
 */
@ApiModel(value = "统一响应消息报文")
public class Result<T> implements Serializable {

    private static final long serialVersionUID = 1L;

    /**
     * 状态码
     *
     * <p>注：不支持自定义设置状态码，需要通过实现 {@link IResultCode} 枚举定义</p>
     */
    @ApiModelProperty(value = "状态码", required = true)
    private int code;

    /**
     * 消息内容
     *
     * <p>注：不支持自定义设置消息内容，需要通过实现 {@link IResultCode} 枚举定义</p>
     */
    @ApiModelProperty(value = "消息内容", required = true)
    private String msg;

    @ApiModelProperty(value = "时间戳", required = true)
    private long time;

    @ApiModelProperty(value = "业务数据")
    @JsonInclude(JsonInclude.Include.NON_NULL)
    private T data;

    private Result() {
        this.time = System.currentTimeMillis();
    }

    private Result(IResultCode resultCode) {
        this(resultCode.getCode(), null, resultCode.getMsg());
    }

    private Result(IResultCode resultCode, T data) {
        this(resultCode.getCode(), data, resultCode.getMsg());
    }

    private Result(int code, T data, String msg) {
        this.code = code;
        this.data = data;
        this.msg = msg;
        this.time = System.currentTimeMillis();
    }

    /**
     * 操作成功
     *
     * @param <T> 泛型标识
     * @return 响应数据
     */
    public static <T> Result<T> success() {
        return new Result<>(ResultCode.SUCCESS);
    }

    /**
     * 操作成功
     *
     * @param resultCode 状态码枚举
     * @param <T>        泛型标识
     * @return 响应数据
     */
    public static <T> Result<T> success(IResultCode resultCode) {
        return new Result<>(resultCode);
    }

    /**
     * 操作成功
     *
     * @param data 业务数据
     * @param <T>  泛型标识
     * @return 响应数据
     */
    public static <T> Result<T> success(T data) {
        return new Result<>(ResultCode.SUCCESS, data);
    }

    /**
     * 操作成功
     *
     * @param resultCode 状态码枚举
     * @param data       业务数据
     * @param <T>        泛型标识
     * @return 响应数据
     */
    public static <T> Result<T> success(IResultCode resultCode, T data) {
        return new Result<>(resultCode, data);
    }

    /**
     * 操作成功
     *
     * @param resultCode 状态码枚举
     * @param data       业务数据
     * @param msgParams  消息内容占位符可变长参数
     * @param <T>        泛型标识
     * @return 响应数据
     */
    public static <T> Result<T> success(IResultCode resultCode, T data, Object... msgParams) {
        if (msgParams == null || msgParams.length == 0) {
            return new Result<>(resultCode, data);
        }

        return new Result<>(resultCode.getCode(), data, MessageFormat.format(resultCode.getMsg(), msgParams));
    }

    /**
     * 操作失败
     *
     * @param <T> 泛型标识
     * @return 响应数据
     */
    public static <T> Result<T> fail() {
        return new Result<>(ResultCode.FAILURE);
    }

    /**
     * 操作失败
     *
     * @param resultCode 状态码枚举
     * @param <T>        泛型标识
     * @return 响应数据
     */
    public static <T> Result<T> fail(IResultCode resultCode) {
        return new Result<>(resultCode);
    }

    /**
     * 操作失败
     *
     * @param data 业务数据
     * @param <T>  泛型标识
     * @return 响应数据
     */
    public static <T> Result<T> fail(T data) {
        return new Result<>(ResultCode.FAILURE, data);
    }

    /**
     * 操作失败
     *
     * @param resultCode 状态码枚举
     * @param data       业务数据
     * @param <T>        泛型标识
     * @return 响应数据
     */
    public static <T> Result<T> fail(IResultCode resultCode, T data) {
        return new Result<>(resultCode, data);
    }

    /**
     * 操作失败
     *
     * @param resultCode 状态码枚举
     * @param data       业务数据
     * @param msgParams  消息内容占位符可变长参数
     * @param <T>        泛型标识
     * @return 响应数据
     */
    public static <T> Result<T> fail(IResultCode resultCode, T data, Object... msgParams) {
        if (msgParams == null || msgParams.length == 0) {
            return new Result<>(resultCode, data);
        }

        return new Result<>(resultCode.getCode(), data, MessageFormat.format(resultCode.getMsg(), msgParams));
    }

    public int getCode() {
        return code;
    }

    public String getMsg() {
        return msg;
    }

    public long getTime() {
        return time;
    }

    public void setTime(long time) {
        this.time = time;
    }

    public T getData() {
        return data;
    }

    public void setData(T data) {
        this.data = data;
    }
}
